# Create your tests here.

import json
import numpy as np
from business.models import ICE, GasBoiler, ElectricBoiler, AR, IceTank, ERU, AirPump, GroundPump, GasTurbine, WindPower, PVP, ARS, Buttery
from scipy import optimize
import xlrd
import threading
import math
from business.models import CalResult, DesignPlan
from django.db.models import Sum, Max
import openpyxl
from DataPlatform.settings import STATIC_ROOT


class Model(object):
    def __init__(self, config):
        self.model = int(config['model']['which'])  # 系统配置模式
        self.buy_gas = int(config['model']['buy_gas'])  # 是否购气
        self.buy_heat = int(config['model']['buy_heat'])  # 是否购热


class CCHPConfig(object):  # 三联供
    def __init__(self, config):
        self.is_selected = config['CCHP']['is_selected']
        self.which = 0 if config['CCHP']['ICE'] else 1
        self.ARS = SubDevices('ARS', config['CCHP']['ARS'])  # 烟气热水机
        self.ICE = SubDevices('ICE', config['CCHP']['ICE'])  # 内燃机
        self.gt = SubDevices('gt', config['CCHP']['gt'])  # 燃气轮机
        self.max_power = float(config['CCHP']['parameter']['max_power']) if config['CCHP']['parameter']['max_power'] else 0


class ARC(object):  # 直燃型吸收式制冷机
    def __init__(self, config):
        self.is_selected = int(config["ar"]["is_selected"])
        self.which = config["ar"]["which"]


class RE(object):  # 可再生能源
    def __init__(self, config):
        self.is_selected = int(config["re"]["is_selected"])
        self.wind = SubDevices('wind', config["re"]["wind"])
        self.solar = SubDevices('solar', config["re"]["solar"])


class SubDevices(object):  # 子设备
    def __init__(self, cat, config):
        self.cat = cat
        self.is_selected = int(config["is_selected"]) if config["is_selected"] else 0
        self.which = config["which"]
        self.max_power = float(config["parameter"]['max_power']) if "parameter" in config and config["parameter"]['max_power'] else 0


class HeatPump(object):  # 热泵
    def __init__(self, config):
        self.is_selected = int(config["hp"]["is_selected"])
        self.gp = SubDevices('gp', config["hp"]['gp'])
        self.ap = SubDevices('ap', config["hp"]['ap'])


class Boiler(object):  # 锅炉
    def __init__(self, config):
        self.is_selected = int(config['boiler']["is_selected"])
        self.gb = SubDevices('gb', config['boiler']['gb'])  # 燃气锅炉
        self.eb = SubDevices('eb', config['boiler']['eb'])  # 电锅炉


class IceStorage(object):  # 冰蓄冷
    def __init__(self, config):
        self.is_selected = int(config['is_selected'])
        self.cu = SubDevices('cu', config['cu'])  # 冷水机组
        self.it = SubDevices('it', config['it'])  # 蓄冰槽
        params = config['parameter']
        self.max_capacity = 0 if not params['max_capacity'] else float(params['max_capacity'])  # 充放功率上限
        self.max_power = float(params['max_power']) if params['max_power'] else 0


class HeatStorage(object):  # 蓄热
    def __init__(self, config):
        self.is_selected = int(config['is_selected'])
        params = config['parameter']
        self.max_capacity = float(params['max_capacity']) if params['max_capacity'] else 0  # 配置容量
        self.max_powerch = float(params['max_powerch']) if params['max_powerch'] else 0  # 充能功率
        self.max_powerdis = float(params['max_powerdis']) if params['max_powerdis'] else 0  # 放能功率
        self.efficiency = float(params['efficiency']) if params['efficiency'] else 0  # 充放功率


class EleStorage(object):  # 蓄电
    def __init__(self, config):
        self.is_selected = int(config['is_selected']) if config['is_selected'] else 0
        self.max_capacity = int(config['parameter']['max_capacity']) if config['parameter']['max_capacity'] else 0
        self.battery = SubDevices('battery', config['battery'])


class ESE(object):  # 储能装置
    def __init__(self, config):
        self.is_selected = int(config['ese']["is_selected"])
        self.ice = IceStorage(config['ese']['ice_storage'])  # 蓄冰
        self.heat_storage = HeatStorage(config['ese']['heat_storage'])  # 蓄热
        self.ele_storage = EleStorage(config['ese']['ele_storage'])  # 蓄电


class CalConfig(object):
    def __init__(self, params):
        config = json.loads(params)
        self.name = config['name']  # 模型命名
        self.desc = config['desc']  # 描述
        self.model = Model(config)  # 系统配置模式
        self.summer_day = config['summer_day']  # 典型夏季日
        self.winter_day = config['winter_day']  # 典型冬季日
        self.opt = config['opt_target']
        self.cchp = CCHPConfig(config)  # 三联供
        self.ar = ARC(config)  # 直燃型吸收式制冷机
        self.re = RE(config)  # 可再生能源
        self.hp = HeatPump(config)  # 热泵
        self.boiler = Boiler(config)  # 锅炉
        self.ese = ESE(config)  # 储能


# 核心计算方法
def calculate(config, item_params, target_hour, target_date, target_wind_hour, target_pvp_hour, d_id, sell_ele, sell_heat, sell_cold,
              target_sheet):
    """
    :param config:规划配置
    :param item_params: 相关参数
    :param target_hour: 目标小时
    :param target_date: 目标日期
    :param target_wind_hour: 单小时风资源数据
    :param target_pvp_hour: 单小时光资源数据
    :param d_id: 配置id
    :param sell_ele: 售卖电能
    :param sell_heat: 售卖热能
    :param sell_cold: 售卖冷能
    :param target_sheet: 目标sheet页（用于保存规划后的结果到excel中）
    :return:
    """
    z = np.zeros((1, 17))[0]  # 系统年费用
    ice = gt = wind = pvp = gp = gb = eb = ars = ap = ar = eru = None

    if config.cchp.is_selected:  # 选择三联供
        which = config.cchp.which
        target_ice = config.cchp.ICE.which
        target_gt = config.cchp.gt.which
        target_ARS = config.cchp.ARS.which
        if which == 0 and target_ice:  # 选择内燃机系统并选择设备
            ice = ICE.objects.get(model_name=target_ice)
        elif which == 0 and not target_ice:  # 未选择设备，采用默认设备
            ice = ICE.objects.get(is_default=1)
        elif which == 1 and target_gt:  # 选择燃气轮机系统并选择设备
            gt = GasTurbine.objects.get(model_name=target_gt)
        elif which == 1 and not target_gt:  # 未选择设备，采用默认设备
            gt = GasTurbine.objects.get(is_default=1)

        if target_ARS:  # 选择烟气热水机
            ars = ARS.objects.get(model_name=target_ARS)
        else:  # 未选择采用默认设备
            ars = ARS.objects.get(is_default=1)
        z[0] = - sell_ele[target_hour % 24]
        z[13] = -sell_heat[target_hour % 24]
        z[14] = -sell_cold[target_hour % 24]
    else:  # 未选择三联供
        z[0] = z[13] = z[14] = 0

    if config.hp.is_selected:  # 选择热泵
        target_gp = config.hp.gp
        if target_gp.is_selected and target_gp.which:  # 选择地源热泵并选择设备
            gp = GroundPump.objects.get(model_name=target_gp.which)
        elif target_gp.is_selected and not target_gp.which:  # 未选择设备，采用默认设备
            gp = GroundPump.objects.get(is_default=1)
        else:  # 未选择地源热泵
            gp = None

        z[1] = ((gp.ppp / 8760) - sell_heat[target_hour % 24] * gp.make_cool_effect if gp else 0)
        target_ap = config.hp.ap  # 选择风冷热泵
        if target_ap.is_selected and target_ap.which:  # 选择风冷热泵型号
            ap = AirPump.objects.get(model_name=target_ap.which)
        elif target_ap.is_selected and not target_ap.which:  # 未选择风冷热泵型号，采用默认设备
            ap = AirPump.objects.get(is_default=1)
        else:
            ap = None  # 未选择风冷热泵
        z[2] = (ap.ppp / 8760) if ap else 0
    else:
        z[2] = 0

    if config.boiler.is_selected:  # 锅炉
        target_gb = config.boiler.gb  # 燃气锅炉
        if target_gb.is_selected and target_gb.which:  # 选择燃气锅炉并选择型号
            gb = GasBoiler.objects.get(model_name=target_gb.which)
        elif target_gb.is_selected and not target_gb.which:  # 未选择型号，采用默认设备
            gb = GasBoiler.objects.get(is_default=1)
        else:  # 未选择燃气锅炉
            gb = None
        z[3] = (gb.ppp / 8760) if gb else 0

        target_eb = config.boiler.eb  # 电锅炉
        if target_eb.is_selected and target_eb.which:  # 选择电锅炉并选择型号
            eb = ElectricBoiler.objects.get(model_name=target_eb.which)
        elif target_eb.is_selected and not target_eb.which:  # 未选择型号，采用默认设备
            eb = ElectricBoiler.objects.get(is_default=1)
        else:  # 未选择锅炉
            eb = None
        z[5] = (eb.ppp / 8760) if eb else 0
    else:  # 未选择锅炉
        z[5] = 0

    if config.ar.is_selected:  # 直燃型吸收式制冷机
        if config.ar.which:  # 选择设备型号
            ar = AR.objects.get(model_name=config.ar.which)
        elif not config.ar.which:  # 未选择型号，采用默认设备
            ar = AR.objects.get(is_default=1)
        else:  # 未选择吸收式制冷机
            ar = None
    z[4] = (ar.ppp / 8760) if ar else 0

    if config.ese.is_selected:  # 储能
        if config.ese.ice.is_selected:  # 选择冰蓄冷
            target_cu = config.ese.ice.cu
            target_ice_storage = target_cu.which
            if target_cu.is_selected and target_ice_storage:
                eru = ERU.objects.get(model_name=target_ice_storage)
            elif target_cu.is_selected and not target_ice_storage:
                eru = ERU.objects.get(is_default=1)
            else:  # 未选择冰蓄冷
                eru = None
            z[6] = (eru.ppp / 8760)
        else:
            z[6] = 0

        if config.ese.ele_storage.is_selected:  # 选择蓄电装置
            which = config.ese.ele_storage.battery.which
            if which:  # 选择电池型号
                z[15] = z[16] = Buttery.objects.values('sp').get(model_name=which)['sp']
            else:  # 未选择型号，采用默认设备
                z[15] = z[16] = Buttery.objects.values('sp').get(is_default=True)['sp']
    else:  # 未选择蓄电装置
        z[15] = z[16] = z[6] = 0

    if config.re.is_selected:  # 选择可再生能源
        target_wind = config.re.wind
        if target_wind.is_selected and target_wind.which:  # 选择风机
            wind = WindPower.objects.values().get(model_name=target_wind.which)
        elif target_wind.is_selected and target_wind.which == '':  # 未选择风机，采用默认设备
            wind = WindPower.objects.values().get(is_default=1)
        else:
            wind = None  # 未选择风机
        target_pvp = config.re.solar
        if target_pvp.is_selected and target_pvp.which:  # 选择光伏
            pvp = PVP.objects.get(model_name=target_pvp.which)  # 选择光伏板型号
        elif target_pvp.is_selected and target_pvp.which == '':  # 未选择光伏板，采用默认设备
            pvp = PVP.objects.get(is_default=1)
        else:
            pvp = None  # 未选择光伏

        tw = wind.copy()

        tw.pop('model_name')
        tw.pop('is_default')
        ppp = tw.pop('ppp')
        z[11] = 0 if wind == "" else max(tw.values()) * ppp  # 风机价格
        z[12] = 0 if pvp == '' else pvp.ppp * pvp.max_power  # 光伏价格
    else:
        z[11] = z[12] = 0  # 未选择可再生能源

    z[7] = item_params["ele_price"] - sell_ele[target_hour % 24]
    z[8], z[9], z[10] = item_params['gas_price'], item_params['heat_price'], item_params['ele_sell_to_net']

    if config.opt == '0':  # 经济性
        pass
    elif config.opt == '1':  # 能源利用率
        if wind and 2 <= target_wind_hour <= 25:
            tw = wind.copy()
            tw.pop('model_name')
            tw.pop('is_default')
            tw.pop('ppp')
            z12 = max(tw.values())
        else:
            z12 = 0
        pvp_max_power = 0 if not pvp else pvp.max_power
        z = np.array([0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0])  # 一次能耗
    else:
        print('错误优化目标')
        return

    e1 = b1 = 0
    # b14 = b15 = 0
    if config.cchp.is_selected:
        if ice:  # 内燃机
            b1 = 1 / (ice.power_effect / 100)  # 耗气量
            e1 = ice.heat_effect / ice.power_effect
        if gt:  # 燃气轮机
            b1 = 1 / gt.generation_effect  # 耗气量
            e1 = gt.heat_effect / gt.generation_effect
    else:
        e1 = b1 = 0
        # b14 = b15 = 0
        print('没有选ccph')

    c2 = d2 = 0
    if gp:  # 地源热泵
        if item_params['heat'] == 0 and item_params['cold'] == 0:  # 根据冷热负荷判断热泵供冷或供热
            c2 = d2 = 0
        elif (not item_params['heat'] == 0) and item_params['cold'] == 0:
            c2 = gp.make_heat_effect
            d2 = 0
        elif item_params['heat'] == 0 and (not item_params['cold'] == 0):
            c2 = 0
            d2 = gp.make_cool_effect
        else:
            c2 = gp.make_heat_effect
            d2 = 0

    # 功率平衡约束，依次为电、气、热、冷平衡，等式左侧为：
    a = np.array([1, -1, -1, 0, 0, -1, -1, 1, 0, 0, -1,
                  0 if wind == '' or (target_wind_hour < 2 or target_wind_hour > 25) else wind['s' + str(target_wind_hour)],
                  0 if pvp == '' else pvp.max_power * target_pvp_hour / 1000, 0, 0, -1, 1])
    b = np.array([-1 * b1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0])

    c = np.array(
        [0, c2, 0, 0 if not gb else gb.heat_effect / 100, 0, 0 if not eb else eb.heat_effect / 100, 0, 0, 0,
         1 if config.model.buy_heat else 0, 0, 0, 0,
         1, 0, 0, 0])

    if eru:  # 选择冰蓄冷
        hour_in_day = target_hour % 24
        if 7 >= hour_in_day >= 0 or 18 >= hour_in_day >= 12:
            d7 = eru.ice_effect
        else:
            d7 = 0
    else:  # 未选择冰蓄冷
        d7 = 0

    d = np.array(
        [0, d2, 0 if not ap else ap.effect, 0, 0 if not ar else ar.cool_effect, 0, d7, 0, 0, 0, 0, 0, 0,
         0, 1, 0, 0])

    if ars:
        e15 = -1 / ars.effect
    else:
        e15 = 0
    e = np.array([e1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, e15, 0, 0])  # 三联供的供电与供冷热关系

    """
    等式👉
    1.电负荷；2.气负荷；3.热负荷；4.冷负荷
    """

    eql = np.array([item_params['ele'], item_params['gas'], item_params['heat'], item_params['cold'], 0])  # 负荷

    xl = np.array([a, b, c, d, e])

    if config.cchp.is_selected:
        max_power = config.cchp.max_power
        if max_power:
            x0 = (0, max_power)  # 用户设置的CCHP供电出力上限
            x13 = (0, max_power * ice.heat_effect / ice.power_effect if ice else max_power * gt.heat_effect / gt.power_effect)
            if ice:  # 选择内燃机系统
                x14 = (0, max_power * ice.heat_effect * ars.effect / ice.power_effect)
            else:  # 选择燃气轮机系统
                x14 = (0, max_power * gt.heat_effect * ars.effect / gt.power_effect)
        else:  # 未设置出力上限
            x0 = (0, None)
            x13 = x14 = (0, None)

    else:  # 未选择CCHP
        x0 = (0, 0)
        x13 = (0, 0)
        x14 = (0, 0)

    if gp:  # 地源热泵
        if config.hp.gp.max_power:
            x1 = (0, config.hp.gp.max_power / gp.make_heat_effect)
        else:
            x1 = (0, None)
    else:
        x1 = (0, 0)

    if ap:  # 风冷热泵
        if config.hp.ap.max_power:  # 填写出力上限
            x2 = (0, config.hp.ap.max_power / ap.effect)
        else:  # 未填写出力上限
            x2 = (0, None)
    else:  # 未选择风冷热泵
        x2 = (0, 0)

    if gb:  # 燃气锅炉
        if config.boiler.gb.max_power:  # 填写出力上限
            x3 = (0, config.boiler.gb.max_power / (gb.heat_effect / 100))
        else:  # 未填写出力上限
            x3 = (0, None)
    else:  # 未选择燃气锅炉
        x3 = (0, 0)

    x4 = (0, None)
    if eb:  # 电锅炉
        if config.boiler.eb.max_power:  # 填写出力上限
            x5 = (0, config.boiler.eb.max_power / (eb.heat_effect / 100))
        else:  # 未填写出力上限
            x5 = (0, None)
    else:  # 未选择电锅炉
        x5 = (0, 0)

    if eru:  # 冷水机组
        if config.ese.ice.max_power:  # 填写出力上限
            x6 = (0, config.ese.ice.max_power / eru.cool_effect)
        else:  # 未填写出力上限
            x6 = (0, None)
    else:  # 未选择冰蓄冷
        x6 = (0, 0)

    x7 = x8 = x9 = x10 = (0, None)
    model_type = config.model.model
    if model_type == 0:  # 孤岛模式
        x7 = x8 = x9 = x10 = (0, 0)
    elif model_type == 1:  # 并网不上网模式
        x7 = (0, None)
        x10 = (0, 0)  # 不上网
        x8 = (0, None if config.model.buy_gas else 0)  # 判断是否购气
        x9 = (0, None if config.model.buy_heat else 0)  # 判断是否购热
    elif model_type == 2:  # 并网上网模式
        x7 = (0, None)
        x10 = (0, None)
        x8 = (0, None if config.model.buy_gas else 0)  # 判断是否购气
        x9 = (0, None if config.model.buy_heat else 0)  # 判断是否购热
    else:
        print('Wrong type')

    x11 = (0, None if config.re.wind.is_selected else 0)
    x12 = (0, None if config.re.solar.is_selected else 0)

    x15 = x16 = (0, config.ese.ele_storage.battery.max_power if config.ese.ele_storage.is_selected else 0)

    bound = (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)

    res = optimize.linprog(z, A_eq=-xl, b_eq=-eql, bounds=bound)  # 求解线性规划

    if gt:
        item_cal = res.x[0] / gt.generation_effect
    elif ice:
        item_cal = res.x[0] / (ice.power_effect / 100)
    else:
        item_cal = 0

    wind_power = wind['s' + str(target_wind_hour)] * res.x[11] if res.x[11] and wind and 2 <= target_wind_hour <= 25 else 0
    pvp_power = res.x[12] * pvp['max_power'] * target_pvp_hour / 1000 if res.x[12] and pvp else 0

    rst = {
        'design_id': d_id,
        'target_date': target_date,
        'target_time': target_hour,
        'ice_os': res.x[0],
        'ice_ig': item_cal,
        'gp_ieh': res.x[1],
        'gp_oh': res.x[1] * c2 if gp else 0,
        'gp_oc': res.x[1] * d2 if gp else 0,
        'ap_ie': res.x[2],
        'ap_oc': res.x[2] * ap.effect if ap else 0,
        'gb_ig': res.x[3],
        'gb_oh': res.x[3] * (gb.heat_effect / 100) if gb else 0,
        'ar_ig': res.x[4],
        'ar_oc': res.x[4] * ar.cool_effect if ar else 0,
        'eb_ie': res.x[5],
        'eb_oh': res.x[5] * (eb.heat_effect / 100) if eb else 0,
        'it_ch': config.ese.ice.max_power / eru.cool_effect if eru and (7 >= (target_hour % 24) >= 0) and item_params['cold'] > 0 else 0,
        'it_dis': res.x[6] * eru.cool_effect if eru and (7 >= (target_hour % 24) >= 0 or 18 >= (target_hour % 24) >= 12) else 0,
        'ele_buy': res.x[7],
        'ele_pri': res.x[7] * item_params['ele_price'],
        'gas_buy': res.x[8],
        'gas_pri': res.x[8] * item_params['gas_price'],
        'heat_buy': res.x[9],
        'heat_pri': res.x[9] * item_params['heat_price'],
        'ele_sell': res.x[10],
        'ele_inc': res.x[10] * item_params['ele_sell_to_net'],
        'wind': res.x[11],
        'PV': res.x[12],
        'cchp_oh': res.x[13],
        'cchp_oc': res.x[14],
        'heat_load': item_params['heat'],
        'cold_load': item_params['cold'],
        'ele_load': item_params['ele'],
        'sell_h': item_params['heat'] * sell_heat[target_hour % 24],
        'sell_c': item_params['cold'] * sell_cold[target_hour % 24],
        'sell_e': item_params['ele'] * sell_ele[target_hour % 24],
        'wind_power': wind_power,
        'pvp_power': pvp_power,
        'co2_em': res.x[8] * 0.589,
        'nox_em': res.x[8] * 0.000378,
        'ele_ch': res.x[15],
        'ele_dis': res.x[16],
        'is_correct': res.success
    }  # 对应计算excel里的结果

    if wind:
        if res.x[7] + res.x[0] + wind_power + pvp_power > res.x[1] + res.x[2] + res.x[5] + res.x[6]:  # 判断是否需要蓄电
            rst['ele_dis'] = 0
        else:
            rst['ele_ch'] = 0
    CalResult(**rst).save()
    target_sheet.append(tuple(rst.values()))
    print(target_hour, res.x, res.success, res.message)
    return res.x[11], res.x[12]


def fill_economic(d_id, light_out, wind_out, ecom_data, who):
    """
    将计算好的数据填入经评文件中
    :param d_id:
    :param light_out:
    :param wind_out:
    :param ecom_data:
    :param who:
    :return:
    """

    # 定义data对象，用于保存数据与excel的对应关系
    data = {
        # 来自文件
        "loan_ratio": (0, 'B5'),
        "capital_ratio": (0, 'B6'),
        "lending_rates": (0, 'B7'),
        "liquidity_ratio": (0, 'B10'),
        "depreciation_period": (0, 'B11'),
        "residual_rate": (0, 'B12'),
        "apia": (0, 'B13'),
        "reserve_rate": (0, 'B14'),
        "e_vat": (0, 'B26'),
        "hc_vat": (0, 'B27'),
        "cgccf": (0, 'B34'),
        "cgcepf": (0, 'B35'),
        "cgcof": (0, 'B37'),
        "scesf": (0, 'B41'),
        "cgcief": (0, 'B36'),
        # 来自求和
        "ice_os": (1, 'D5'),  # 三联供发电
        'ele_buy': (1, 'D6'),  # 购电
        'gb_oh': (1, 'D7'),  # 燃气锅炉供热
        'gp_oh': (1, 'D8'),  # 地源热泵供热
        'eb_oh': (1, 'D9'),  # 电锅炉供热
        'cchp_oh': (1, 'D11'),  # 三联供供热
        'heat_buy': (1, 'D13'),  # 购热
        'gp_oc': (1, 'D15'),  # 地源热泵供冷
        'ap_oc': (1, 'D16'),  # 风冷热泵供冷
        'cchp_oc': (1, 'D17'),  ##三联供供冷
        'it_dis': (1, 'D18'),  # 冰蓄冷
        'ar_oc': (1, 'D14'),  # 吸收式制冷机供冷
        'ele_load': (1, 'B20'),  # 电负荷
        'heat_load': (1, 'B21'),  # 热负荷
        'cold_load': (1, 'B22'),  # 冷负荷
        'gas_buy': (1, 'B26'),  # 购气

        'gb_ig': (8, 'D7'),
        'eb_ie': (8, 'D8'),
        'it_ch': (8, 'D9'),
        'ar_ig': (8, 'D10'),
        'gp_ieh': (8, 'D11'),
        'ap_ie': (8, 'D12'),
        # 'ice_ig': (8, 'D13'),
        # 'ice_ig': (8, 'D14'),
        # 'ice_ig': (8, 'D14'),
        'ele_pri': (8, 'D17'),
        'heat_pri': (8, 'D18'),
        # 来自计算结果
        'light_output': (1, 'C2'),  # 光伏发电量
        'wind_output': (1, 'C3'),  # 风力发电量
        # 最大值结果（根据最大输入功率计算设备投资）
        'pvp_max': (0, 'G4'),  # 光伏价格
        'wind_max': (0, 'G5'),  # 风机投资
        'gb_max': (0, 'G6'),  # 燃气锅炉投资
        'eb_max': (0, 'G7'),  # 电锅炉投资
        'eru_max': (0, 'G8'),  # 冷水机组投资
        'ar_max': (0, 'G9'),  # 吸收式制冷机投资
        'gp_max': (0, 'G10'),  # 地源热泵投资
        'ap_max': (0, 'G11'),  # 风冷热泵投资
        'ICE_max': (0, 'G12'),  # 内燃机系统投资
        # 'gt_max': (0, 'G13'),  # 燃气轮机系统投资
    }

    sum_data = CalResult.objects.filter(design_id=d_id).aggregate(ice_os=Sum("ice_os"), ele_buy=Sum('ele_buy'), gb_oh=Sum('gb_oh'),
                                                                  eb_oh=Sum('eb_oh'), cchp_oh=Sum('cchp_oh'), heat_buy=Sum('heat_buy'),
                                                                  gp_oc=Sum('gp_oc'), ap_oc=Sum('ap_oc'), cchp_oc=Sum('cchp_oc'),
                                                                  it_dis=Sum('it_dis'), ar_oc=Sum('ar_oc'), ele_load=Sum('ele_load'),
                                                                  heat_load=Sum('heat_load'), cold_load=Sum('cold_load'),
                                                                  gas_buy=Sum('gas_buy'), gp_oh=Sum('gp_oh'), gb_ig=Sum('gb_ig'),
                                                                  eb_ie=Sum('eb_ie'), it_ch=Sum('it_ch'), ar_ig=Sum('ar_ig'),
                                                                  gp_ieh=Sum('gp_ieh'), ap_ie=Sum('ap_ie'), ele_pri=Sum('ele_pri'),
                                                                  heat_pri=Sum('heat_pri'))

    max_data = CalResult.objects.filter(design_id=d_id).aggregate(pvp_max=Max('pvp_power'), wind_max=Max('wind_power'), gb_max=Max('gb_oh'),
                                                                  eb_max=Max('eb_oh'), eru_max=Max('it_dis'), ar_max=Max('ar_oc'),
                                                                  gp_max=Max('gp_oh'), ap_max=Max('ap_oc'), ICE_max=Max('ice_os'))

    design = DesignPlan.objects.values('summer_day', 'winter_day', 'gt_which',
                                       'ice_which', 'gp_which', 'ap_which', 'gb_which', 'ar_which', 'eb_which', 'cu_which',
                                       'wind_which', 'solar_which', 'cu_which', 'ar_which', 'ice_which').get(belongs__account=who,
                                                                                                             design_id=d_id)

    target_path = STATIC_ROOT + '/business/params_file/' + 'fs_template.xlsx'
    copy_path = STATIC_ROOT + '/business/user_params_file/' + who + "_economic_" + d_id + '.xlsx'

    book = openpyxl.load_workbook(target_path)

    # 将由规划出的结果有关经评的数据填入sheet中
    for k, v in ecom_data.items():
        sheet, loc = data[k]
        book.worksheets[sheet][loc].value = v

    # 将需要求和的结果填入结果中
    for k, v in sum_data.items():
        sheet, loc = data[k]
        book.worksheets[sheet][loc].value = v

    # 以下为最大出力 * 设备的单价（ppp:price per power)
    sheet, loc = data['wind_max']
    if design['wind_which']:
        book.worksheets[sheet][loc].value = WindPower.objects.get(model_name=design['wind_which']).ppp * max_data['pvp_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['pvp_max']
    if design['solar_which']:
        book.worksheets[sheet][loc].value = PVP.objects.get(model_name=design['solar_which']).ppp * max_data['pvp_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['gb_max']
    if design['gb_which']:
        book.worksheets[sheet][loc].value = GasBoiler.objects.get(model_name=design['gb_which']).ppp * max_data['gb_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['eb_max']
    if design['eb_which']:
        book.worksheets[sheet][loc].value = ElectricBoiler.objects.get(model_name=design['eb_which']).ppp * max_data['eb_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['eru_max']
    if design['cu_which']:
        book.worksheets[sheet][loc].value = ERU.objects.get(model_name=design['cu_which']).ppp * max_data['eru_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['ar_max']
    if design['ar_which']:
        book.worksheets[sheet][loc].value = AR.objects.get(model_name=design['ar_which']).ppp * max_data['ar_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['gp_max']
    if design['gp_which']:
        book.worksheets[sheet][loc].value = GroundPump.objects.get(model_name=design['gp_which']).ppp * max_data['gp_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['ap_max']
    if design['ar_which']:
        print('ar_which', design['ar_which'])
        book.worksheets[sheet][loc].value = AR.objects.get(model_name=design['ar_which']).ppp * max_data['ap_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['ICE_max']
    if design['ice_which']:
        book.worksheets[sheet][loc].value = ICE.objects.get(model_name=design['ice_which']).ppp * max_data['ICE_max']
    else:
        book.worksheets[sheet][loc].value = 0

    sheet, loc = data['gt_max']
    if design['gt_which']:
        book.worksheets[sheet][loc].value = GasTurbine.objects.get(model_name=design['gt_which']).ppp * max_data['ICE_max']
    else:
        book.worksheets[sheet][loc].value = 0
    sheet1 = book.worksheets[0]
    sheet1['C2'].value = light_out
    sheet1['C3'].value = wind_out
    # 数据保存
    book.save(copy_path)


class CalThread(threading.Thread):
    def __init__(self, config, data_file, light_file, wind_file, design_id, economic_data, who):

        self.config, self.data_file, self.light_file, self.wind_file, self.design_id = config, data_file, light_file, wind_file, design_id
        self.who = who
        self.economic_data = economic_data
        super(CalThread, self).__init__()
        self.prc = 0
        self.msg = ''

        # 将结果模板excel拷贝后生成出属于用户本次规划的一份
        target_path = STATIC_ROOT + '/business/params_file/' + 'result_temp.xlsx'
        copy_path = STATIC_ROOT + '/business/user_params_file/' + who + "_result_" + design_id + '.xlsx'
        self.save_path = copy_path
        book = openpyxl.load_workbook(target_path)
        self.target_book = book
        book.save(copy_path)
        #########################################

    def run(self):
        """
        线程运行方法，
        :return:
        """
        config = CalConfig(self.config)
        data_work_boot = xlrd.open_workbook(self.data_file)
        data_sheet = data_work_boot.sheets()[0]
        price_sheet = data_work_boot.sheets()[1]  # 购买能源价钱页
        sell_sheet = data_work_boot.sheets()[2]  # 售卖能源价钱页
        row_num = data_sheet.nrows
        item_params = {'ele_price': 0, 'gas_price': 0, 'heat_price': 0, 'ele_sell_to_net': 0}
        wind_sheet = light_sheet = None

        if self.light_file:
            light_file = xlrd.open_workbook(self.light_file)
            light_sheet = light_file.sheets()[0]
        if self.wind_file:
            wind_file = xlrd.open_workbook(self.wind_file)
            wind_sheet = wind_file.sheets()[0]

        model = config.model.model

        if model == 0:  # 孤岛模式
            sell_ele = sell_heat = sell_cold = ele_price = gas_price = heat_price = [0 for i in range(24)]
        if model == 1:  # 并网不上网模式
            ele_price = [price_sheet.cell_value(i, 1) for i in range(1, price_sheet.nrows)]
            gas_price = [price_sheet.cell_value(i, 2) for i in range(1, price_sheet.nrows)]
            heat_price = [price_sheet.cell_value(i, 3) for i in range(1, price_sheet.nrows)]

            sell_ele = [sell_sheet.cell_value(i, 1) for i in range(1, sell_sheet.nrows)]
            sell_heat = [sell_sheet.cell_value(i, 3) for i in range(1, sell_sheet.nrows)]
            sell_cold = [sell_sheet.cell_value(i, 4) for i in range(1, sell_sheet.nrows)]
        else:  # 并网上网模式
            ele_price = [price_sheet.cell_value(i, 1) for i in range(1, price_sheet.nrows)]
            gas_price = [price_sheet.cell_value(i, 2) for i in range(1, price_sheet.nrows)]
            heat_price = [price_sheet.cell_value(i, 3) for i in range(1, price_sheet.nrows)]

            sell_ele = [sell_sheet.cell_value(i, 1) for i in range(1, sell_sheet.nrows)]
            sell_heat = [sell_sheet.cell_value(i, 3) for i in range(1, sell_sheet.nrows)]
            sell_cold = [sell_sheet.cell_value(i, 4) for i in range(1, sell_sheet.nrows)]

        pvp_output = 0
        wind_ele_output = 0

        for i in range(1, row_num):
            item_params['cold'] = float(data_sheet.cell_value(i, 3)) if data_sheet.cell_value(i, 3) else 0
            item_params['ele'] = float(data_sheet.cell_value(i, 4)) if data_sheet.cell_value(i, 4) else 0
            item_params['gas'] = float(data_sheet.cell_value(i, 5)) if data_sheet.cell_value(i, 5) else 0
            item_params['heat'] = float(data_sheet.cell_value(i, 2)) if data_sheet.cell_value(i, 2) else 0
            target_hour = int(data_sheet.cell_value(i, 1))
            target_date = data_sheet.cell_value(i, 0)
            if model == 0:  # 孤岛模式
                if config.re.wind.is_selected:
                    target_wind_hour = math.floor(float(wind_sheet.cell_value(i, 2)))
                else:
                    target_wind_hour = 0
                if config.re.solar.is_selected:
                    target_light_hour = light_sheet.cell_value(i, 1)
                else:
                    target_light_hour = 0
                wind_count, pvp_count = calculate(config, item_params, target_hour, target_date, target_wind_hour, target_light_hour,
                                                  self.design_id, sell_ele, sell_heat, sell_cold, self.target_book.worksheets[0])
                if target_wind_hour:
                    if target_wind_hour < 2 or target_wind_hour > 25:  # 风速超出风机功率曲线的风速范围
                        item_wind_output = 0  # 出力为0
                    else:  # 风速未超出范围，出力为对应风速下的风机出力
                        item_wind_output = WindPower.objects.values('s' + str(target_wind_hour)).get(model_name=config.re.wind.which)
                    wind_ele_output += wind_count * item_wind_output['s' + str(target_wind_hour)]
                if target_light_hour:
                    max_out = PVP.objects.values('max_power').get(model_name=config.re.solar.which)
                    pvp_output += pvp_count * target_light_hour / 1000 * max_out['max_power']
            elif model == 1:  # 并网不上网模式
                item_params['gas_price'] = gas_price[int(data_sheet.cell_value(i, 1)) % 24] if config.model.buy_gas else 0
                item_params['heat_price'] = heat_price[int(data_sheet.cell_value(i, 1)) % 24] if config.model.buy_heat else 0
                item_params['ele_price'] = ele_price[int(data_sheet.cell_value(i, 1)) % 24]

                if config.re.wind.is_selected:
                    target_wind_hour = math.floor(float(wind_sheet.cell_value(i, 2)))
                else:
                    target_wind_hour = 0
                if config.re.solar.is_selected:
                    target_light_hour = light_sheet.cell_value(i, 1)
                else:
                    target_light_hour = 0
                wind_count, pvp_count = calculate(config, item_params, target_hour, target_date, target_wind_hour, target_light_hour,
                                                  self.design_id, sell_ele, sell_heat, sell_cold, self.target_book.worksheets[0])
                if target_wind_hour:
                    if target_wind_hour < 2 or target_wind_hour > 25:
                        item_wind_output = 0
                    else:
                        model_name = config.re.wind.which
                        if model_name:
                            item_wind_output = WindPower.objects.values('s' + str(target_wind_hour)).get(model_name=model_name)[
                                's' + str(target_wind_hour)]
                        else:
                            item_wind_output = WindPower.objects.values('s' + str(target_wind_hour)).get(is_default=True)[
                                's' + str(target_wind_hour)]

                    wind_ele_output += wind_count * item_wind_output
                if target_light_hour:
                    max_out = PVP.objects.values('max_power').get(model_name=config.re.solar.which)
                    pvp_output += pvp_count * target_light_hour / 1000 * max_out['max_power']
            else:  # 并网上网模式
                item_params['gas_price'] = gas_price[int(data_sheet.cell_value(i, 1)) % 24] if config.model.buy_gas else 0
                item_params['heat_price'] = heat_price[int(data_sheet.cell_value(i, 1)) % 24] if config.model.buy_heat else 0
                item_params['ele_price'] = ele_price[int(data_sheet.cell_value(i, 1)) % 24]
                item_params['ele_sell_to_net'] = sell_ele[int(data_sheet.cell_value(i, 1)) % 24]

                if config.re.wind.is_selected:
                    target_wind_hour = math.floor(float(wind_sheet.cell_value(i, 2)))
                else:
                    target_wind_hour = 0
                if config.re.solar.is_selected:
                    target_light_hour = light_sheet.cell_value(i, 1)
                else:
                    target_light_hour = 0
                wind_count, pvp_count = calculate(config, item_params, target_hour, target_date, target_wind_hour, target_light_hour,
                                                  self.design_id, sell_ele, sell_heat, sell_cold, self.target_book.worksheets[0])
                if target_wind_hour:
                    if target_wind_hour < 2 or target_wind_hour > 25:
                        item_wind_output = 0
                    else:
                        model_name = config.re.wind.which
                        if model_name:
                            item_wind_output = WindPower.objects.values('s' + str(target_wind_hour)).get(model_name=model_name)[
                                's' + str(target_wind_hour)]
                        else:
                            item_wind_output = WindPower.objects.values('s' + str(target_wind_hour)).get(is_default=True)[
                                's' + str(target_wind_hour)]

                    wind_ele_output += wind_count * item_wind_output
                if target_light_hour:
                    max_out = PVP.objects.values('max_power').get(model_name=config.re.solar.which)
                    pvp_output += pvp_count * target_light_hour / 1000 * max_out['max_power']

            self.prc = float('%.2f' % (i / 8760 * 100))
            self.msg = '正在计算中'

        # 保存数据
        self.target_book.save(self.save_path)
        # 计算完成，放入经评数据
        fill_economic(self.design_id, pvp_output, wind_ele_output, self.economic_data, self.who)
        self.prc = 100
        self.msg = '规划完成'

    def get_result(self):
        # print(self.prc, self.msg)
        return self.prc, self.msg
